#!/usr/bin/env node

/**
 * Vision Analyzer Security Audit Tool
 *
 * Comprehensive security assessment for production deployment
 */

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

// Security audit configuration
const SECURITY_CONFIG = {
    // Files and directories to audit
    auditTargets: [
        { path: '.', type: 'directory', name: 'Project Root' },
        { path: 'lib', type: 'directory', name: 'Core Library' },
        { path: 'config', type: 'directory', name: 'Configuration' },
        { path: 'scripts', type: 'directory', name: 'Scripts' },
        { path: 'tests', type: 'directory', name: 'Test Files' },
        { path: 'package.json', type: 'file', name: 'Package Configuration' },
        { path: '.env.example', type: 'file', name: 'Environment Template' },
        { path: '.env.production', type: 'file', name: 'Production Environment' }
    ],

    // Security checks
    securityChecks: {
        credentials: {
            patterns: [
                /api[_-]?key\s*[:=]\s*['"`]([a-zA-Z0-9_-]{20,})['"`]/gi,
                /secret\s*[:=]\s*['"`]([a-zA-Z0-9_-]{20,})['"`]/gi,
                /password\s*[:=]\s*['"`]([^\s'"`]{8,})['"`]/gi,
                /token\s*[:=]\s*['"`]([a-zA-Z0-9._-]{20,})['"`]/gi,
                /private[_-]?key\s*[:=]\s*['"`]([^\s'"`]{20,})['"`]/gi
            ],
            severity: 'HIGH'
        },

        suspiciousImports: {
            patterns: [
                /require\s*\(\s*['"`]child_process['"`]\s*\)/g,
                /require\s*\(\s*['"`]fs['"`]\s*\)/g,
                /require\s*\(\s*['"`]net['"`]\s*\)/g,
                /require\s*\(\s*['"`]http['"`]\s*\)/g,
                /require\s*\(\s*['"`]https['"`]\s*\)/g,
                /require\s*\(\s*['"`]exec['"`]\s*\)/g,
                /require\s*\(\s*['"`]spawn['"`]\s*\)/g
            ],
            severity: 'MEDIUM'
        },

        hardcodedUrls: {
            patterns: [
                /https?:\/\/[^\s'"`]+\.(api|service|server)\.com/gi,
                /https?:\/\/localhost:\d+/g,
                /https?:\/\/127\.0\.0\.1:\d+/g,
                /https?:\/\/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/g
            ],
            severity: 'LOW'
        },

        weakCrypto: {
            patterns: [
                /md5\s*\(/gi,
                /sha1\s*\(/gi,
                /crypto\.createHash\s*\(\s*['"`]md5['"`]/gi,
                /crypto\.createHash\s*\(\s*['"`]sha1['"`]/gi,
                /createCipher\s*\(/gi,  // Deprecated in favor of createCipheriv
                /createDecipher\s*\(/gi
            ],
            severity: 'HIGH'
        },

        evalUsage: {
            patterns: [
                /eval\s*\(/gi,
                /Function\s*\(/gi,
                /setTimeout\s*\(\s*['"`][^'"`]*['"`]\s*,/gi,
                /setInterval\s*\(\s*['"`][^'"`]*['"`]\s*,/gi
            ],
            severity: 'HIGH'
        },

        sqlInjection: {
            patterns: [
                /\+\s*['"`][^'"`]*['"`]\s*\+/gi,  // String concatenation
                /query\s*\(\s*['"`][^'"`]*\$\{[^}]*\}['"`]\s*\)/gi  // Template literals
            ],
            severity: 'HIGH'
        }
    },

    // File permissions to check
    filePermissions: {
        '600': ['.env*', '*.key', '*.pem', '*.p12', 'id_rsa*'],
        '644': ['*.json', '*.js', '*.md', '*.txt'],
        '755': ['*.sh', 'node_modules/', 'scripts/']
    },

    // Dependencies to check for known vulnerabilities
    vulnerablePackages: [
        'lodash', 'request', 'underscore', 'moment', 'axios'
    ]
};

class SecurityAuditor {
    constructor() {
        this.issues = [];
        this.stats = {
            filesScanned: 0,
            linesScanned: 0,
            issuesFound: 0,
            severityCounts: { LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0 }
        };
    }

    /**
     * Run comprehensive security audit
     */
    async runAudit() {
        console.log('🔒 Vision Analyzer Security Audit');
        console.log('=================================\n');

        // Environment check
        this.checkEnvironment();

        // File system security
        await this.auditFileSystem();

        // Code security analysis
        await this.auditCodeSecurity();

        // Dependency security
        await this.auditDependencies();

        // Configuration security
        await this.auditConfiguration();

        // Display results
        this.displayResults();

        // Generate recommendations
        this.generateSecurityRecommendations();

        // Save audit report
        await this.saveAuditReport();
    }

    /**
     * Check basic environment security
     */
    checkEnvironment() {
        console.log('🌍 Environment Security Check');
        console.log('-----------------------------');

        // Check Node.js version
        const nodeVersion = process.version;
        const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);

        if (majorVersion < 18) {
            this.addIssue('CRITICAL', 'Environment',
                `Outdated Node.js version ${nodeVersion}. Please upgrade to v18+ for security patches.`);
        } else {
            console.log(`✓ Node.js version: ${nodeVersion} (secure)`);
        }

        // Check environment variables
        const suspiciousEnvVars = ['API_KEY', 'SECRET', 'PASSWORD', 'TOKEN'];
        const exposedVars = suspiciousEnvVars.filter(varName => process.env[varName]);

        if (exposedVars.length > 0) {
            this.addIssue('HIGH', 'Environment',
                `Sensitive environment variables detected: ${exposedVars.join(', ')}`);
        } else {
            console.log('✓ No sensitive environment variables exposed');
        }

        // Check file permissions
        console.log('✓ File permissions check completed');
        console.log('');
    }

    /**
     * Audit file system security
     */
    async auditFileSystem() {
        console.log('📁 File System Security Audit');
        console.log('-------------------------------');

        for (const target of SECURITY_CONFIG.auditTargets) {
            if (!fs.existsSync(target.path)) {
                continue;
            }

            console.log(`Auditing: ${target.name}`);

            if (target.type === 'directory') {
                await this.auditDirectory(target.path, target.name);
            } else {
                await this.auditFile(target.path, target.name);
            }
        }

        console.log(`✓ Scanned ${this.stats.filesScanned} files, ${this.stats.linesScanned} lines`);
        console.log('');
    }

    /**
     * Audit directory recursively
     */
    async auditDirectory(dirPath, dirName) {
        try {
            const items = fs.readdirSync(dirPath);

            for (const item of items) {
                const itemPath = path.join(dirPath, item);
                const stat = fs.statSync(itemPath);

                // Skip node_modules and .git
                if (item === 'node_modules' || item === '.git' || item === '.DS_Store') {
                    continue;
                }

                if (stat.isDirectory()) {
                    await this.auditDirectory(itemPath, `${dirName}/${item}`);
                } else {
                    await this.auditFile(itemPath, `${dirName}/${item}`);
                }
            }
        } catch (error) {
            this.addIssue('MEDIUM', 'File System',
                `Cannot access directory ${dirPath}: ${error.message}`);
        }
    }

    /**
     * Audit individual file
     */
    async auditFile(filePath, fileName) {
        try {
            // Skip binary files and large files
            const stat = fs.statSync(filePath);
            if (stat.size > 1024 * 1024 || this.isBinaryFile(filePath)) {
                return;
            }

            const content = fs.readFileSync(filePath, 'utf8');
            this.stats.filesScanned++;
            this.stats.linesScanned += content.split('\n').length;

            // Run all security checks
            this.runSecurityChecks(content, fileName, filePath);

            // Check file permissions
            this.checkFilePermissions(filePath, fileName);

        } catch (error) {
            // Ignore read permission errors for now
        }
    }

    /**
     * Run all security checks on file content
     */
    runSecurityChecks(content, fileName, filePath) {
        for (const [checkName, checkConfig] of Object.entries(SECURITY_CONFIG.securityChecks)) {
            for (const pattern of checkConfig.patterns) {
                const matches = content.match(pattern);
                if (matches) {
                    for (const match of matches) {
                        // Find line number
                        const lines = content.split('\n');
                        let lineNumber = 0;
                        for (let i = 0; i < lines.length; i++) {
                            if (lines[i].includes(match)) {
                                lineNumber = i + 1;
                                break;
                            }
                        }

                        this.addIssue(checkConfig.severity, checkName,
                            `Security issue in ${fileName}:${lineNumber} - ${this.getIssueDescription(checkName, match)}`,
                            { file: filePath, line: lineNumber, match: match });
                    }
                }
            }
        }
    }

    /**
     * Get human-readable issue description
     */
    getIssueDescription(checkName, match) {
        const descriptions = {
            credentials: `Potential hardcoded credential detected: ${match.substring(0, 50)}...`,
            suspiciousImports: `Suspicious module import: ${match}`,
            hardcodedUrls: `Hardcoded URL detected: ${match}`,
            weakCrypto: `Weak cryptographic algorithm: ${match}`,
            evalUsage: `Dynamic code execution: ${match}`,
            sqlInjection: `Potential SQL injection: ${match.substring(0, 50)}...`
        };
        return descriptions[checkName] || `Security issue: ${match}`;
    }

    /**
     * Check file permissions
     */
    checkFilePermissions(filePath, fileName) {
        try {
            const stat = fs.statSync(filePath);
            const mode = (stat.mode & parseInt('777', 8)).toString(8);

            // Check for overly permissive files
            if (fileName.includes('.env') && mode !== '600') {
                this.addIssue('HIGH', 'File Permissions',
                    `Environment file ${fileName} has permissive permissions: ${mode} (should be 600)`);
            }

            if (fileName.includes('.key') && mode !== '600') {
                this.addIssue('HIGH', 'File Permissions',
                    `Private key file ${fileName} has permissive permissions: ${mode} (should be 600)`);
            }

        } catch (error) {
            // Skip permission check errors
        }
    }

    /**
     * Audit dependencies for vulnerabilities
     */
    async auditDependencies() {
        console.log('📦 Dependency Security Audit');
        console.log('---------------------------');

        try {
            const packageJsonPath = './package.json';
            if (!fs.existsSync(packageJsonPath)) {
                console.log('⚠️  package.json not found');
                return;
            }

            const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
            const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };

            console.log(`Checking ${Object.keys(dependencies).length} dependencies...`);

            // Check for known vulnerable packages
            for (const [pkgName, version] of Object.entries(dependencies)) {
                if (SECURITY_CONFIG.vulnerablePackages.includes(pkgName)) {
                    this.addIssue('MEDIUM', 'Dependencies',
                        `Package ${pkgName}@${version} may have known vulnerabilities. Consider updating or replacing.`);
                }
            }

            // Check for excessive dependencies
            if (Object.keys(dependencies).length > 50) {
                this.addIssue('LOW', 'Dependencies',
                    `High number of dependencies (${Object.keys(dependies).length}). Consider reducing attack surface.`);
            }

            console.log('✓ Dependency security check completed');

        } catch (error) {
            this.addIssue('MEDIUM', 'Dependencies',
                `Failed to audit dependencies: ${error.message}`);
        }

        console.log('');
    }

    /**
     * Audit configuration security
     */
    async auditConfiguration() {
        console.log('⚙️  Configuration Security Audit');
        console.log('------------------------------');

        // Check .env.example for best practices
        if (fs.existsSync('.env.example')) {
            const content = fs.readFileSync('.env.example', 'utf8');

            if (!content.includes('API_KEY') && !content.includes('SECRET')) {
                this.addIssue('MEDIUM', 'Configuration',
                    '.env.example should include API key configuration examples');
            }
        }

        // Check for production config exposure
        if (fs.existsSync('.env.production')) {
            this.addIssue('HIGH', 'Configuration',
                'Production environment file (.env.production) should not be committed to version control');
        }

        // Check for default credentials
        const configFiles = ['config.json', 'default.json', 'settings.json'];
        for (const configFile of configFiles) {
            if (fs.existsSync(configFile)) {
                try {
                    const content = fs.readFileSync(configFile, 'utf8');
                    if (content.includes('admin') || content.includes('password') || content.includes('secret')) {
                        this.addIssue('MEDIUM', 'Configuration',
                            `Configuration file ${configFile} may contain default credentials`);
                    }
                } catch (error) {
                    // Skip read errors
                }
            }
        }

        console.log('✓ Configuration security check completed');
        console.log('');
    }

    /**
     * Audit code security patterns
     */
    async auditCodeSecurity() {
        console.log('🔍 Code Security Analysis');
        console.log('-------------------------');

        // This is integrated into the file system audit above
        console.log('✓ Code security analysis completed');
        console.log('');
    }

    /**
     * Add security issue to the list
     */
    addIssue(severity, category, description, details = {}) {
        const issue = {
            severity,
            category,
            description,
            details,
            timestamp: new Date().toISOString()
        };

        this.issues.push(issue);
        this.stats.issuesFound++;
        this.stats.severityCounts[severity]++;
    }

    /**
     * Display audit results
     */
    displayResults() {
        console.log('🚨 SECURITY AUDIT RESULTS');
        console.log('==========================');

        console.log(`Files scanned: ${this.stats.filesScanned}`);
        console.log(`Lines analyzed: ${this.stats.linesScanned}`);
        console.log(`Issues found: ${this.stats.issuesFound}`);
        console.log('');

        // Display issues by severity
        const severities = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'];
        for (const severity of severities) {
            const count = this.stats.severityCounts[severity];
            if (count > 0) {
                console.log(`${severity}: ${count} issue${count > 1 ? 's' : ''}`);
            }
        }

        if (this.issues.length === 0) {
            console.log('\n🎉 Excellent! No security issues found.');
            return;
        }

        console.log('\n📋 Detailed Issues:');
        console.log('-------------------');

        // Group issues by category
        const issuesByCategory = {};
        for (const issue of this.issues) {
            if (!issuesByCategory[issue.category]) {
                issuesByCategory[issue.category] = [];
            }
            issuesByCategory[issue.category].push(issue);
        }

        for (const [category, issues] of Object.entries(issuesByCategory)) {
            console.log(`\n${category}:`);
            for (const issue of issues) {
                const icon = this.getSeverityIcon(issue.severity);
                console.log(`  ${icon} [${issue.severity}] ${issue.description}`);
                if (issue.details.file) {
                    console.log(`      Location: ${issue.details.file}:${issue.details.line}`);
                }
            }
        }
    }

    /**
     * Get severity icon
     */
    getSeverityIcon(severity) {
        const icons = {
            CRITICAL: '🚨',
            HIGH: '⚠️',
            MEDIUM: '⚡',
            LOW: 'ℹ️'
        };
        return icons[severity] || '•';
    }

    /**
     * Generate security recommendations
     */
    generateSecurityRecommendations() {
        console.log('\n💡 SECURITY RECOMMENDATIONS');
        console.log('============================');

        if (this.issues.length === 0) {
            console.log('✅ Security posture is excellent. Continue following security best practices.');
            return;
        }

        const recommendations = [];

        // Critical issues recommendations
        const criticalIssues = this.issues.filter(i => i.severity === 'CRITICAL');
        if (criticalIssues.length > 0) {
            recommendations.push('🚨 CRITICAL: Address all critical security issues immediately before production deployment');
        }

        // High severity recommendations
        const highIssues = this.issues.filter(i => i.severity === 'HIGH');
        if (highIssues.length > 0) {
            recommendations.push('⚠️  HIGH: Review and fix all high-severity security issues');
        }

        // Category-specific recommendations
        const categories = [...new Set(this.issues.map(i => i.category))];
        for (const category of categories) {
            switch (category) {
                case 'Credentials':
                    recommendations.push('🔑 Remove all hardcoded credentials and use environment variables');
                    break;
                case 'Dependencies':
                    recommendations.push('📦 Update dependencies and implement automated vulnerability scanning');
                    break;
                case 'File Permissions':
                    recommendations.push('🔒 Restrict file permissions on sensitive files (600 for .env files)');
                    break;
                case 'Configuration':
                    recommendations.push('⚙️  Review configuration security and avoid committing sensitive configs');
                    break;
                case 'Code Security':
                    recommendations.push('🛡️  Review code for security vulnerabilities and implement secure coding practices');
                    break;
            }
        }

        // General recommendations
        recommendations.push('🔍 Implement automated security testing in CI/CD pipeline');
        recommendations.push('📊 Set up security monitoring and alerting');
        recommendations.push('🔄 Regularly schedule security audits and penetration testing');
        recommendations.push('📚 Keep team trained on security best practices');

        recommendations.forEach((rec, index) => {
            console.log(`${index + 1}. ${rec}`);
        });
    }

    /**
     * Save audit report to file
     */
    async saveAuditReport() {
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        const filename = `security-audit-${timestamp}.json`;
        const filepath = path.join('./audits', filename);

        // Ensure audits directory exists
        const auditsDir = './audits';
        if (!fs.existsSync(auditsDir)) {
            fs.mkdirSync(auditsDir, { recursive: true });
        }

        const reportData = {
            timestamp: new Date().toISOString(),
            stats: this.stats,
            issues: this.issues,
            config: SECURITY_CONFIG,
            summary: {
                totalIssues: this.issues.length,
                criticalIssues: this.stats.severityCounts.CRITICAL,
                highIssues: this.stats.severityCounts.HIGH,
                mediumIssues: this.stats.severityCounts.MEDIUM,
                lowIssues: this.stats.severityCounts.LOW,
                securityScore: this.calculateSecurityScore()
            }
        };

        fs.writeFileSync(filepath, JSON.stringify(reportData, null, 2));
        console.log(`\n💾 Audit report saved to: ${filepath}`);
    }

    /**
     * Calculate security score
     */
    calculateSecurityScore() {
        if (this.issues.length === 0) return 100;

        const weights = { CRITICAL: 10, HIGH: 5, MEDIUM: 2, LOW: 1 };
        const totalWeight = this.issues.reduce((sum, issue) => sum + weights[issue.severity], 0);
        const maxPossibleWeight = this.stats.filesScanned * 0.1; // Assumed issues per file

        return Math.max(0, 100 - (totalWeight / maxPossibleWeight * 100));
    }

    // Utility methods
    isBinaryFile(filePath) {
        const ext = path.extname(filePath).toLowerCase();
        const binaryExts = ['.jpg', '.jpeg', '.png', '.gif', '.zip', '.tar', '.gz', '.exe', '.dll', '.so'];
        return binaryExts.includes(ext);
    }
}

// CLI interface
async function main() {
    const auditor = new SecurityAuditor();

    try {
        await auditor.runAudit();

        const score = auditor.calculateSecurityScore();
        console.log(`\n🎯 SECURITY SCORE: ${score.toFixed(1)}/100`);

        if (score >= 90) {
            console.log('🏆 EXCELLENT security posture');
        } else if (score >= 70) {
            console.log('✅ GOOD security posture with minor improvements needed');
        } else if (score >= 50) {
            console.log('⚠️  MODERATE security posture - improvements needed');
        } else {
            console.log('🚨 POOR security posture - immediate action required');
        }

        process.exit(0);
    } catch (error) {
        console.error('❌ Security audit failed:', error.message);
        console.error(error.stack);
        process.exit(1);
    }
}

// Run if called directly
if (require.main === module) {
    main();
}

module.exports = SecurityAuditor;